package com.smart.other;


import cn.hutool.core.util.StrUtil;
import com.smart.common.entities.constant.SmartConstant;
import com.smart.manager.weixin.mp.entities.bodys.RValidAuthBody;
import com.smart.manager.weixin.mp.handler.EventMessageHandler;
import com.smart.manager.weixin.mp.handler.TextMessageHandler;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.*;

/**
 * @author Administrator
 */
@Api(tags = "微信公众号回调地址")
@RestController
@Log4j2
@RequestMapping(SmartConstant.OTHER_API_PREFIX + "wxmp/callback")
@RequiredArgsConstructor
public class WxmpCallback {



    private final WxMpService wxMpService;

    private final TextMessageHandler textMessageHandler;

    private final EventMessageHandler eventMessageHandler;

    /**
     * 微信验签
     */
    @ResponseBody
    @ApiOperation(value = "微信接口-接入验签")
    @GetMapping("{appId}")
    public String validAuth(@PathVariable String appId, RValidAuthBody body) {
        log.warn(body.toString());
        String signature = body.getSignature();
        String nonce = body.getNonce();
        String echostr = body.getEchostr();
        String timestamp = body.getTimestamp();
        if (!StrUtil.isAllNotBlank(signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法!");
        }

        if (wxMpService.switchoverTo(appId).checkSignature(timestamp, nonce, signature)) {
            return echostr;
        }

        return "非法的数据请求";
    }


    /**
     * 消息转发---中转站
     * 每次微信端的消息都会来到这里进行分发
     * 对微信公众号相关的一些动作，都以报文形式推送到该接口，
     * 根据请求的类型，进行路由分发处理
     */
    @PostMapping(value = "{appId}", produces = "application/xml; charset=UTF-8")
    public String decodeMessage(@RequestParam(name = "encrypt_type", required = false) String encryptType,
                                @RequestParam(name = "signature", required = false) String signature,
                                @RequestParam(name = "timestamp", required = false) String timestamp,
                                @RequestParam(name = "nonce", required = false) String nonce,
                                @RequestParam(name = "msg_signature", required = false) String msgSignature,
                                @RequestBody String requestBody,
                                @PathVariable String appId) {


        //定义一个字符变量 用来回复微信服务区
        String outMsg = "";
        try {
            outMsg = this.handleMsg(appId, encryptType, signature, timestamp, nonce, msgSignature, requestBody);
        } catch (Exception e) {
            log.error("响应请求异常,error:{},{}", e.getMessage(), e);
        }
        return outMsg;
    }


    /**
     * 消息中转站 用于收到的消息解密 和返回的消息加密
     * handleMsg 返回微信需要的数据请求格式
     */
    @Nullable
    private String handleMsg(String appid, String encryptType, String signature, String timestamp, String nonce, String msgSignature, String requestBody) {

        WxMpService wxMpService = this.wxMpService.switchoverTo(appid);

        if ("aes".equals(encryptType)) {
            if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
                throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
            }
        }

        //定义一个变量 用于接收收到的消息正文
        WxMpXmlMessage inMessage;
        boolean isEncrypt = "aes".equals(encryptType);
        if (isEncrypt) {
            //如果加密了  需要对收到的内容进行解密
            inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(), timestamp, nonce, msgSignature);
        } else {
            inMessage = WxMpXmlMessage.fromXml(requestBody);
        }


        //返回的内容字符串
        WxMpXmlOutMessage outMessage = buildMsgRouter(wxMpService).route(inMessage);
        if (outMessage == null) {
            return "";
        }
        String outStrMsg = outMessage.toXml();
        //如果加密了需要对返回的内容进行加密
        if (isEncrypt) {
            WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpService.getWxMpConfigStorage());
            outStrMsg = cryptUtil.encrypt(outStrMsg);
        }
        return outStrMsg;
    }


    /**
     * 回复内容路由处理器
     */
    private WxMpMessageRouter buildMsgRouter(WxMpService wxMpService) {
        final WxMpMessageRouter wxRouter = new WxMpMessageRouter(wxMpService);
        //收到文本消息是的处理程序
        wxRouter.rule().async(true).msgType(WxConsts.XmlMsgType.TEXT).handler(textMessageHandler).end();
        //收到事件消息走事件消息处理器
        wxRouter.rule().async(true).msgType(WxConsts.XmlMsgType.EVENT).handler(eventMessageHandler).end();
        //用户发送位置消息的处理程序
        // wxRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION).handler(locationMessageHandler).end();

        //没有定义的消息都走这个处理器进行消息回复
        wxRouter.rule().async(true).handler(textMessageHandler).end();
        return wxRouter;
    }


}
